import logging

from django.db.models import Q
from django.shortcuts import render
from drf_yasg2 import openapi
from drf_yasg2.utils import swagger_auto_schema
from rest_framework import viewsets, status
from erp_system.models import MenuModel, PermissionsModel
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from PAA_ERP.apps.erp_system.serializer.menu_serializer import MenuSerializer

# Create your views here.


# 得到日志输出对象logging
logger = logging.getLogger('erp')

'''
功能菜单的模型类
128是父类带的
1.新增
2.查询单个功能菜单
3.查询所有功能菜单
4.查询某个父类菜单下面的所有子菜单列表
5.查询多有的顶级菜单
6.删除每一个功能菜单
7.批量删除多个功能菜单  #传参ids=【1，2，3】
8.修改功能惨淡
'''


class MenuView(viewsets.ModelViewSet):
    '''
    create:
    新增菜单,

    可以返回参数：为env参数，其实 delete_flag,create_time,update_time不用传参，return:添加之后的对象

    retrieve:
    查询单个菜单对象

    list:
    查询所有的菜单

    如果参数中有pid则查询某一个父菜单下的所有子菜单列表，pid=0表示查询所有顶级菜单列表

    update:
    修改菜单

    partial_update:
    局部修改菜单，修改任意指定的属性

    destroy:
    删除指定id的菜单那


    get_menu_by_permission:
    当前用户，根据权限查询那些，拥有get权限的功能菜单列表（返回树形菜单）

    功能菜单列表信息，status：（200）成功，return：功能菜单信息列表
    '''
    # permission_classes = [IsAuthenticated,]
    queryset = MenuModel.objects.filter(delete_flag=0).all()
    serializer_class = MenuSerializer

    def get_queryset(self):
        logger.info(f'当前登录用户是:{self.request.user}')
        '''
        两种情况
        1：查询所有菜单列表，不需要传递id
        2：查询某个父类下面的所有子菜单的的列表，需要传递一个参数pid==0的时候，查询所有顶级菜单列表
        '''
        query_param = self.request.query_params.get('pid', None)
        if query_param:
            pid = int(query_param)
            if pid == 0:  # 查询所有顶级菜单列表
                return MenuModel.objects.filter(parent__isnull=True, delete_flag=0).all()
            else:  # 查询个父类下面的所有子菜单的的列表
                return MenuModel.objects.filter(parent__id=pid, delete_flag=0).all()
        else:
            return MenuModel.objects.filter(delete_flag=0).all()

    def destroy(self, request, *args, **kwargs):
        '''
        修改一下删除标记为delete_flag=1
        '''
        menu = self.get_object()
        menu.delete_flag = '1'
        menu.save()
        # 可能该菜单下面还有子菜单，这些子菜单也要修改
        MenuModel.objects.filter(parent__id=menu.id).update(delete_flag='1')

        return Response(status=status.HTTP_204_NO_CONTENT)

    del_ids = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description='选择那些需要删除的id（主键）列表')
    })

    # action装饰器可以接收两个参数：
    # methods: 声明该action对应的请求方式，列表传递
    # detail: 声明该action的路径是否与单一资源对应，及是否是xxx/<pk>/action方法名/
    #   True 表示路径格式是xxx/<pk>/action方法名/
    #   False 表示路径格式是xxx/action方法名/
    @swagger_auto_schema(method='delete', request_body=del_ids, operation_description='批量删除')
    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        delete_ids = request.data.get('ids')
        if not delete_ids:
            return Response(data={'detail': '参数错误,ids为必传参数'}, status=status.HTTP_400_BAD_REQUEST)
        elif not isinstance(delete_ids, list):
            return Response(data={'detail': 'ids格式错误,必须为List'}, status=status.HTTP_400_BAD_REQUEST)
        # 先查询传递过来的功能菜单
        MenuModel.objects.filter(id__in=delete_ids).update(delete_flag=1)
        # 删除所有的子菜单
        for m_id in delete_ids:
            MenuModel.objects.filter(parent__id=m_id).update(delete_flag=1)
        return Response(status=status.HTTP_204_NO_CONTENT)

    # @action(methods=['delete'], detail=False)
    # def multiple_delete(self, request, *args, **kwargs):
    #     delete_ids = request.data.get('ids')
    #     if not delete_ids:
    #         return Response(data={'detail': '参数错误,ids为必传参数'},status=status.HTTP_400_BAD_REQUEST)
    #     elif not isinstance(delete_ids, list):
    #         return Response(data={'detail': 'ids格式错误,必须为List'},status=status.HTTP_400_BAD_REQUEST)  # 先删除传递过来的功能菜单
    #     MenuModel.objects.filter(id__in=delete_ids).update(delete_flag=1)  # 删除 所有的子功能菜单
    #     for m_id in delete_ids:
    #         MenuModel.objects.filter(parent__id=m_id).update(delete_flag=1)
    #     return Response(status=status.HTTP_204_NO_CONTENT)
    @action(methods=['get'], detail=False)
    def get_menu_by_permission(self, request, *args, **kwargs):
        # 当前用户，根据权限查询那些，拥有get权限的功能菜单列表
        # 第一步查询当前登录用户，拥有的权限id列表,注意：values_list返回列表，values返回字典，（字段名为建）
        permission_ids = request.user.roles.values_list('permissions', flat=True).distinct()

        # 第二部：查询拥有get权限的功能菜单的id列表
        # 注意：特殊情况，父菜单没有任何method，所以如果是父菜单的权限也应该要出现
        # id__in=permission_ids意思id在什么里面
        menu_id = PermissionsModel.objects.filter(id__in=permission_ids) \
            .filter(Q(method='GET') | Q(is_menu=True)).values_list('menu', flat=True)
        # 第三步 :根据id查询菜单列表
        menu_list = MenuModel.objects.filter(Q(id__in=menu_id, delete_flag=0)).all()
        serializer = MenuSerializer(instance=menu_list, many=True)
        # 通过serializer把menu_list变为字典
        # 变成一个树形结构才可以
        tree_dict = {}  # 代表一个父菜单
        tree_data = []  #
        for item in serializer.data:
            tree_dict[item['id']] = item
        for i in tree_dict:
            if tree_dict[i]['parent']:
                pid = tree_dict[i]['parent']
                parent = tree_dict[pid]
                parent.setdefault('children', []).append(tree_dict[i])
            else:  # 是否父菜单
                tree_data.append(tree_dict[i])
        return Response(tree_data)
